package com.hxgis.oc.util.geotools;


import org.geotools.data.DefaultTransaction;
import org.geotools.data.Transaction;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class GeoConvertor {
    SimpleFeatureBuilder featureBuilder;
    GeometryFactory geometryFactory;
    List<SimpleFeature> features = new ArrayList<>();
    SimpleFeatureType featureType;

    private SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();

    public SimpleFeatureTypeBuilder createPointTypeBuilder(){
        builder = new SimpleFeatureTypeBuilder();
        builder.setName("Location");
        builder.setCRS(DefaultGeographicCRS.WGS84);
        builder.add("the_geom", Point.class);
        return builder;
    }

    public void addPoint(float x,float y,Object[] attributes){
        if(geometryFactory == null){
            featureType = builder.buildFeatureType();
            geometryFactory = JTSFactoryFinder.getGeometryFactory();
            featureBuilder = new SimpleFeatureBuilder(featureType);
        }

        Point point = geometryFactory.createPoint(new Coordinate(x, y));
        featureBuilder.add(point);
        if(attributes != null){
            for(Object o : attributes){
                featureBuilder.add(o);
            }
        }
        SimpleFeature feature = featureBuilder.buildFeature(null);
        features.add(feature);
    }

    public void save(File file){
        if(features.size() == 0){
            return;
        }

        try {
            ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
            Map<String, Serializable> params = new HashMap<>();
            params.put("url", file.toURI().toURL());
            params.put("create spatial index", Boolean.TRUE);

            ShapefileDataStore newDataStore =
                    (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
            newDataStore.setCharset(Charset.forName("GBK"));
            newDataStore.createSchema(featureType);
            Transaction transaction = new DefaultTransaction("create");

            String typeName = newDataStore.getTypeNames()[0];
            SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
            // SimpleFeatureType SHAPE_TYPE = featureSource.getSchema();
            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
            /*
             * SimpleFeatureStore has a method to add features from a
             * SimpleFeatureCollection object, so we use the ListFeatureCollection
             * class to wrap our list of features.
             */
            SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features);
            featureStore.setTransaction(transaction);
            try {
                featureStore.addFeatures(collection);
                transaction.commit();
            } catch (Exception problem) {
                problem.printStackTrace();
                transaction.rollback();
            } finally {
                transaction.close();
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
